package com.honey.core;


import java.io.File;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.java.plugin.PluginLifecycleException;
import org.java.plugin.boot.Application;
import org.java.plugin.boot.ApplicationPlugin;
import org.java.plugin.util.ExtendedProperties;

import com.honey.configureation.ConfigurationPlugin;
import com.honey.configureation.Context;
import com.honey.configureation.holder.MappingEnvironmentHolder.MappingEnvironment;
import com.honey.core.calculator.JavaNameCalculator;
import com.honey.core.calculator.MappingCalculator;
import com.honey.core.callback.CallbackCompilation;
import com.honey.core.compiler.CompilationDescriptor;
import com.honey.core.compiler.CompilationType;
import com.honey.core.dbmapping.ActualSchemaName;
import com.honey.core.dbmapping.introspect.IntrospectSchema;
import com.honey.core.dbmapping.introspect.IntrospectSchemaColumn;
import com.honey.core.dbmapping.structure.StructureType;
import com.honey.core.feature.Feature;
import com.honey.core.feature.SourceCodeFeature;
import com.honey.core.formater.CodeFormater;
import com.honey.core.generator.BusinessLayerCompilation;
import com.honey.core.generator.CodeCompilation;
import com.honey.core.generator.PresentationLayerCompilation;
import com.honey.core.notify.Notify;
import com.honey.core.notify.Signal;
import com.honey.core.processor.ColumnProcessor;
import com.honey.core.types.FullyQualifiedJavaType;
import com.honey.core.utils.ObjectFactory;
import com.honey.core.writer.CompilationWriter;

/**
 * 代码生成器核心插件
 * @author Administrator
 *
 */
@SuppressWarnings("unchecked")
public class CorePlugin extends ApplicationPlugin implements Application {
	
	/** 系统环境 */ 
	private Context context ; 
	
	/**
	 * 初始化应用程序<br />
	 * 内容主要是加载配置文件
	 */
	protected Application initApplication(ExtendedProperties properties, String[] arg) throws Exception {
		ConfigurationPlugin configurationPlugin = ActivateExtensionPlugin.activateConfigurationPlugin(this, properties, arg) ;
		context = configurationPlugin.getContextInstant();
		ActivateExtensionPlugin.activateSessionListenerPlugin(this);
		
		return this;
	}

	protected void doStart() throws Exception {/*Nop*/}
	
	protected void doStop() throws Exception {/*Nop*/}

	private IntrospectSchema introspectSchema ;
	
	private IntrospectSchemaColumn introspectSchemaColumn ;
	
	@Override
	public void startApplication() throws Exception {
		List<MappingEnvironment> mappings = this.context.getMappingEnvironmentHolder().getMappings();
		for(MappingEnvironment mapping : mappings ){
			ActualSchemaName actualSchemaName = new ActualSchemaName(mapping.getTableName(),"Order");
			introspectSchema =  introspectedSchema(actualSchemaName);
			StructureType schemaType = introspectSchema.getSchema().getSchemaType();
			switch ( schemaType){
				case TABLE:
				case VIEW:
				case TEMPORARY:
					introspectSchemaColumn = introspectedTableColumn(actualSchemaName);
					break ;
				case PROCEDURE:
					introspectSchemaColumn = introspectProcedureParameter(actualSchemaName) ;
					break ;
			}
			System.out.println(introspectSchema.getSchema());
			//Presentation layer
			//Business layer
			//Action layer
			
	//		switch ( schemaType){
	//		case TABLE:
	//		case VIEW:
	//		case TEMPORARY:
	//			System.out.println( "All Column : "+((IntrospectTableColumn)column).allColumns());
	//			System.out.println("--===========================================================================--");
	//			System.out.println( "PrimaryKey Column : "+((IntrospectTableColumn)column).primaryKeyColumns());
	//			System.out.println("--===========================================================================--");
	//			System.out.println( "Base Column : "+((IntrospectTableColumn)column).baseColumns());
	//			System.out.println("--===========================================================================--");
	//			System.out.println( "Blob Column : "+((IntrospectTableColumn)column).blobColumns());
	//			break ;
	//		case PROCEDURE:
	//			System.out.println( "All Column : "+((IntrospectProcedureParameter)column).allColumns());
	//			System.out.println("--===========================================================================--");
	//			System.out.println( "In Column : "+((IntrospectProcedureParameter)column).parameterInColumns());
	//			System.out.println("--===========================================================================--");
	//			System.out.println( "Out Column : "+((IntrospectProcedureParameter)column).parameterOutColumns());
	//			break ;
	//		}
			
			List<CompilationDescriptor[]> compilationDescriptors = new ArrayList<CompilationDescriptor[]>();
			
			//持久层
			PresentationLayerCompilation presentationLayer = getPresentationLayer();
			if( presentationLayer != null ){
				CompilationDescriptor[] presentationClass = null;
				presentationClass = presentationLayer.compilation(introspectSchema,introspectSchemaColumn);
				if( presentationClass!= null && presentationClass.length>0 ){
					compilationDescriptors.add(presentationClass);
				}
			}
			
			//业务层
			BusinessLayerCompilation businessLayer = getBusinessLayer();
			if( businessLayer != null && presentationLayer != null){
				CompilationDescriptor[]  businessClass = null;
				businessLayer.setPresentationLayerCompilation(presentationLayer);
				businessClass = businessLayer.compilation(introspectSchema,introspectSchemaColumn);
				if( businessClass!= null && businessClass.length>0 ){
					compilationDescriptors.add(businessClass);
				}
			}
			
			//通用类
			CompilationDescriptor[] generalCompilation = generator(introspectSchema,introspectSchemaColumn);
			if( generalCompilation!= null && generalCompilation.length>0 ){
				compilationDescriptors.add(generalCompilation);
			}

			if( compilationDescriptors.size() > 0 ){
				for(CompilationDescriptor[] compilation : compilationDescriptors ){
					for(CompilationDescriptor compilationDescriptor : compilation){
						if(compilationDescriptor != null){
							runExtensionPoint(compilationDescriptor);
						}
					}
				}
			}
		}
	}
	
	private void runExtensionPoint(CompilationDescriptor compilationDescriptor ) throws PluginLifecycleException{
		runCallbackCompilation(compilationDescriptor);
		
		runSourceCodeFeature(compilationDescriptor);
		
		runCompilationWriter(compilationDescriptor);
		
		runCodeFormater(compilationDescriptor);
	}
	
	private void runSourceCodeFeature(CompilationDescriptor compilationDescriptor) throws PluginLifecycleException{
		Map<CompilationType, SourceCodeFeature> featurePluginS =this.getSourceCodeFeature();
		CompilationType  kind =compilationDescriptor.getCompilationType();
		SourceCodeFeature feature = featurePluginS.get(kind);
		if( feature != null){
			//当前版本不处理插件返回的Feature对象.
			boolean bool = feature.calculationFeature(compilationDescriptor.getCompilation(), kind,compilationDescriptor.getCharset());
			boolean isChecked = feature.originalChecksum(compilationDescriptor.getWorkSpace(), 
					compilationDescriptor.getCompilation().getType(), 
					compilationDescriptor.getCompilationType(),
					null, 
					compilationDescriptor.getCharset());
			Feature[] features = feature.getFeatures();
			compilationDescriptor.setFeature(isChecked, features);
			//System.out.println(features);
		}
	}
	
	private void runCallbackCompilation(CompilationDescriptor compilationDescriptor) throws PluginLifecycleException{
		CallbackCompilation[] callbackCompilations =this.callbackCompilation();
		if(callbackCompilations != null ){
			for( CallbackCompilation callback : callbackCompilations){
				if( callback!= null ) callback.execute(compilationDescriptor);
			}
		}
	}
	
	/**
	 * 运行写入文件插件
	 * @param compilationDescriptor
	 * @throws PluginLifecycleException
	 */
	private void runCompilationWriter(CompilationDescriptor compilationDescriptor) throws PluginLifecycleException{
		CompilationWriter writer = getCompilationWriter();
		writer.writeToFile(compilationDescriptor);
		compilationDescriptor.setSourceCodeFile( writer.getTargetSourceFile() );
	}
	
	/**
	 * 格式化文件
	 * @param compilationDescriptor
	 * @throws PluginLifecycleException
	 */
	private void runCodeFormater(CompilationDescriptor compilationDescriptor) throws PluginLifecycleException{
		Map<CompilationType, CodeFormater> map = this.getCodeFormater(); 
		if( map!= null && map.size() > 0 ){
			CodeFormater cf = map.get( compilationDescriptor.getCompilationType() );
			if(cf != null){
				try {
					File source = compilationDescriptor.getSourceCodeFile();
					boolean isWrite = source.canWrite();
					if( !isWrite  ){
						source.setWritable(true);
					}
					cf.format(source , compilationDescriptor.getCharset());
					if( !isWrite  ){
						source.setWritable(isWrite);
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	}
	/**
	 * 获取数据库结构的扩展点.扩展点类是com.honey.core.dbmapping.introspectIntrospectSchema
	 * @return
	 * @throws ClassNotFoundException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws SQLException
	 * @throws PluginLifecycleException
	 */
	private IntrospectSchema introspectedSchema(ActualSchemaName actualSchemaName ) throws PluginLifecycleException{
		IntrospectSchema answer = null;
		com.honey.core.Extension<CorePlugin> extension = ObjectFactory.getExtensionClass( this , PluginConstent.EXTENSION_INTROSPECT_SCHEMA);
		if(extension instanceof IntrospectSchema){
			answer = (IntrospectSchema)extension;
			answer.introspect(actualSchemaName);
		}
		return answer;
	}
	
	/**
	 * 
	 * 获取数据库列信息
	 * @throws ClassNotFoundException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws SQLException
	 * @throws PluginLifecycleException
	 */
	private IntrospectSchemaColumn introspectedTableColumn(ActualSchemaName actualSchemaName ) throws PluginLifecycleException{
		IntrospectSchemaColumn answer = null;
		com.honey.core.Extension<CorePlugin>  extension = ObjectFactory.getExtensionClass( this , PluginConstent.EXTENSION_INTROSPECT_TABLE_COLUMN);
		if(extension instanceof IntrospectSchemaColumn){
			answer = (IntrospectSchemaColumn)extension;
			answer.introspect(actualSchemaName);
		}
		return answer;
	}
	
	/**
	 * 持久层插件
	 * @return
	 * @throws PluginLifecycleException
	 */
	public PresentationLayerCompilation getPresentationLayer()throws PluginLifecycleException{
		PresentationLayerCompilation answer = null;
		com.honey.core.Extension<CorePlugin>  extension = ObjectFactory.getExtensionClass( this , PluginConstent.EXTENSION_PRESENTATION_LAYER);
		if(extension instanceof PresentationLayerCompilation){
			answer = (PresentationLayerCompilation)extension;
		}
		return answer;
	}
	
	/**
	 * 业务层插件
	 * @return
	 * @throws PluginLifecycleException
	 */
	public BusinessLayerCompilation getBusinessLayer()throws PluginLifecycleException{
		BusinessLayerCompilation answer = null;
		com.honey.core.Extension<CorePlugin>  extension = ObjectFactory.getExtensionClass( this , PluginConstent.EXTENSION_BUSINESS_LAYER);
		if(extension instanceof BusinessLayerCompilation){
			answer = (BusinessLayerCompilation)extension;
		}
		return answer;
	}
	
	
	
	/**
	 * 存储过程参数
	 * @param actualSchemaName
	 * @return
	 * @throws ClassNotFoundException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws SQLException
	 * @throws PluginLifecycleException
	 */
	private IntrospectSchemaColumn introspectProcedureParameter(ActualSchemaName actualSchemaName ) throws ClassNotFoundException, InstantiationException, IllegalAccessException, SQLException, PluginLifecycleException{		
		IntrospectSchemaColumn answer = null;
		com.honey.core.Extension<CorePlugin>  extension = ObjectFactory.getExtensionClass(this, PluginConstent.EXTENSION_INTROSPECT_PROCEDURE_PARAMETER);
		if(extension instanceof IntrospectSchemaColumn){
			answer = (IntrospectSchemaColumn)extension;
			answer.introspect(actualSchemaName);
		}
		return answer;
	}

	/**
	 * 代码生成器链
	 * @param introspectSchema
	 * @param introspectSchemaColumn
	 * @throws ClassNotFoundException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws SQLException
	 * @throws PluginLifecycleException
	 */
	private CompilationDescriptor[] generator(IntrospectSchema introspectSchema,IntrospectSchemaColumn introspectSchemaColumn)throws ClassNotFoundException, InstantiationException, IllegalAccessException, SQLException, PluginLifecycleException{		
		com.honey.core.Extension<CorePlugin>  []extensions = ObjectFactory.getExtensionClasses(this, PluginConstent.EXTENSION_CODE_GENERATOR);
		ArrayList<CompilationDescriptor> list = new ArrayList<CompilationDescriptor>();
		CompilationDescriptor[] compilationArray = null;
		for(com.honey.core.Extension<CorePlugin> extension : extensions){
			if(extension instanceof CodeCompilation){
				CodeCompilation cg = (CodeCompilation)extension;
				compilationArray = cg.compilation(introspectSchema, introspectSchemaColumn);
				if(compilationArray != null && compilationArray.length>0) 
					list.addAll( Arrays.asList( compilationArray ) );
			}
		}
		return list.toArray( new CompilationDescriptor[list.size()] );
	}
	
	/**
	 * 数据列处理器链
	 * @return
	 * @throws ClassNotFoundException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws SQLException
	 * @throws PluginLifecycleException
	 */
	public ColumnProcessor[] getColumnProcessor()throws PluginLifecycleException{		
		ColumnProcessor[] answer = null;
		com.honey.core.Extension<CorePlugin>  []extensions = ObjectFactory.getExtensionClasses(this, PluginConstent.EXTENSION_COLUMN_PROCESSOR);
		answer = new ColumnProcessor[extensions.length] ;
		int i =0;
		for(com.honey.core.Extension<CorePlugin> extension : extensions){
			answer[i]=(ColumnProcessor)extension;
			i++ ;
		}
		return answer;
	}
	
	/**
	 * 获取java名称计算器
	 * @return 
	 * @throws PluginLifecycleException
	 */
	public JavaNameCalculator getJavaNameCalculator() throws PluginLifecycleException{
		JavaNameCalculator answer = null;
		com.honey.core.Extension<CorePlugin>  extension = ObjectFactory.getExtensionClass(this, PluginConstent.EXTENSION_JAVA_NAME_CALCULATOR);
		if( extension instanceof JavaNameCalculator){
			answer = (JavaNameCalculator)extension;
		}
		return answer;
	}
	
	/**
	 * 获取数据库名称转换到java名称计算器
	 * @return
	 * @throws PluginLifecycleException
	 */
	public MappingCalculator getMappingCalculator() throws PluginLifecycleException{
		MappingCalculator answer = null;
		com.honey.core.Extension<CorePlugin>  extension = ObjectFactory.getExtensionClass(this, PluginConstent.EXTENSION_MAPPING_CALCULATOR);
		if( extension instanceof MappingCalculator){
			answer = (MappingCalculator)extension;
		}
		return answer;
	}
	
	/**
	 * 获取编译文件写入器
	 * @return
	 * @throws PluginLifecycleException
	 */
	public CompilationWriter getCompilationWriter() throws PluginLifecycleException{
		CompilationWriter answer = null;
		com.honey.core.Extension<CorePlugin>  extension =  ObjectFactory.getExtensionClass(this, PluginConstent.EXTENSION_COMPILATION_WRITER);
		if( extension instanceof CompilationWriter){
			answer = (CompilationWriter)extension;
		}
		return answer;
	}
	
	/**
	 * 获取回调处理的插件
	 * @return
	 * @throws PluginLifecycleException
	 */
	public CallbackCompilation[] callbackCompilation() throws PluginLifecycleException{
		CallbackCompilation [] answer = null ;
		com.honey.core.Extension<CorePlugin>  []extensions = ObjectFactory.getExtensionClasses(this, PluginConstent.EXTENSION_CALLBACK_COMPILATION);
		answer = new CallbackCompilation[extensions.length] ;
		int i =0;
		for(com.honey.core.Extension<CorePlugin> extension : extensions){
			answer[i]=(CallbackCompilation)extension;
			i++ ;
		}
		return answer;
	}

	/**
	 * 获取代码格式化的插件
	 * @return
	 * @throws PluginLifecycleException
	 */
	public Map<CompilationType, CodeFormater> getCodeFormater() throws PluginLifecycleException{
		Map<CompilationType, CodeFormater> answer = null;
		com.honey.core.Extension<CorePlugin>  []extensions = ObjectFactory.getExtensionClasses(this, PluginConstent.EXTENSION_CODE_FORMATER);
		answer = new HashMap<CompilationType, CodeFormater> ();
		for(com.honey.core.Extension<CorePlugin> extension : extensions){
			CodeFormater cf = (CodeFormater)extension;
			for(CompilationType fileType : cf.supportCompilationTypes() ){
				answer.put( fileType , cf);
			}
		}
		return answer;
	}
	
	/**
	 * 获取通知的插件
	 * @return
	 * @throws PluginLifecycleException
	 */
	public Map<Class<Signal>, List<Notify>> getNotify() throws PluginLifecycleException{
		Map<Class<Signal>, List<Notify>> answer = null;
		com.honey.core.Extension<CorePlugin>  []extensions = ObjectFactory.getExtensionClasses(this, PluginConstent.EXTENSION_Notify);
		answer = new HashMap<Class<Signal>, List<Notify>>();
		for(com.honey.core.Extension<CorePlugin> extension : extensions){
			Notify cf = (Notify)extension;
			Class<Signal>[] s = cf.supportSignal();
			if( s != null ){
				for( Class<Signal> clazz : s ){
					List<Notify> list = answer.get(clazz);
					if(list == null){
						list = new  ArrayList<Notify>();
						answer.put(clazz, list);
					}
					list.add(cf);
				}
			}
		}
		return answer ;
	}
	
	/**
	 * 抽取源码特征插件
	 * @return
	 * @throws PluginLifecycleException
	 */
	public Map<CompilationType, SourceCodeFeature> getSourceCodeFeature() throws PluginLifecycleException{
		Map<CompilationType, SourceCodeFeature> answer = null;
		com.honey.core.Extension<CorePlugin>  []extensions = ObjectFactory.getExtensionClasses(this, PluginConstent.SOURCE_CODE_FEATURE);
		answer = new HashMap<CompilationType, SourceCodeFeature>();
		for(com.honey.core.Extension<CorePlugin> extension : extensions){
			SourceCodeFeature cf = (SourceCodeFeature)extension;
			CompilationType[] types = cf.supportCompilationTypes();
			if( types != null)
			for( CompilationType type : types ){
				answer.put(type, cf);
			}
		}
		return answer;
	}
	
	/**
	 * 通知插件
	 * @param signal
	 * @throws PluginLifecycleException
	 */
	public void notify(Signal signal ) throws PluginLifecycleException{
		(new NotifyToPlugin( getNotify())).runNotify(signal) ;
	}
	
	public IntrospectSchema getIntrospectSchema() {
		return introspectSchema;
	}

	public IntrospectSchemaColumn getIntrospectSchemaColumn() {
		return introspectSchemaColumn;
	}

	public Context getContextInstant() {
		return context;
	}
}
